using System;
using System.Collections;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.Caching;

namespace PickGold.Charting
{
	internal class DefaultImageHandler : IChartStorageHandler
	{
		private const int AccessTimeout = 10000;//0x2710;

		private static string _PrivacyKeyName = "_pk";
		private static byte[] _PrivacyMarker = new Guid("332E3AB032904BCEA82B249C25E65CB6").ToByteArray();
		private static ReaderWriterLock _ReaderWriterLock = new ReaderWriterLock();
		private static Hashtable _StorageData = new Hashtable();

		internal DefaultImageHandler()
		{
		}

		private static byte[] GetHashData()
		{
			var currentGuidKey = ChartHttpHandler.CurrentGuidKey;
			var sessionID = ChartHttpHandler.Settings.SessionID;
			if (string.IsNullOrEmpty(currentGuidKey) || string.IsNullOrEmpty(sessionID))
				return new byte[0];

			var bytes = Encoding.UTF8.GetBytes(sessionID + "/" + currentGuidKey);
			using (var sha = new SHA1CryptoServiceProvider())
				return sha.ComputeHash(bytes);
		}

		private void NotSupportedStorageType(ChartHttpHandlerSettings settings)
		{
			throw new NotSupportedException(SR.ExceptionHttpHandlerStorageTypeUnsupported(settings.StorageType.ToString()));
		}

		void IChartStorageHandler.Delete(string key)
		{
			var settings = ChartHttpHandler.Settings;
			if (settings.StorageType == ChartHttpHandlerStorageType.Process)
			{
				_ReaderWriterLock.AcquireWriterLock(AccessTimeout);
				try
				{
					_StorageData.Remove(key);
					_StorageData.Remove(key + _PrivacyKeyName);
				}
				finally
				{
					_ReaderWriterLock.ReleaseWriterLock();
				}
				return;
			}

			if (settings.StorageType == ChartHttpHandlerStorageType.File)
			{
				File.Delete(settings.Directory + key);
				return;
			}

			if (settings.StorageType == ChartHttpHandlerStorageType.Cache)
			{
				HttpContext.Current.Cache.Remove(key);
				return;
			}

			this.NotSupportedStorageType(settings);
		}

		bool IChartStorageHandler.Exists(string key)
		{
			var settings = ChartHttpHandler.Settings;
			if (settings.StorageType == ChartHttpHandlerStorageType.Process)
			{
				_ReaderWriterLock.AcquireReaderLock(AccessTimeout);
				try
				{
					return _StorageData.Contains(key);
				}
				finally
				{
					_ReaderWriterLock.ReleaseReaderLock();
				}
			}

			if (settings.StorageType == ChartHttpHandlerStorageType.File)
				return File.Exists(settings.Directory + key);

			if (settings.StorageType == ChartHttpHandlerStorageType.Cache)
				return (HttpContext.Current.Cache[key] is byte[]);

			this.NotSupportedStorageType(settings);
			return false;
		}

		byte[] IChartStorageHandler.Load(string key)
		{
			var settings = ChartHttpHandler.Settings;
			var buffer = new byte[0];
			if (settings.StorageType == ChartHttpHandlerStorageType.Process)
			{
				_ReaderWriterLock.AcquireReaderLock(AccessTimeout);
				try
				{
					if ((settings.PrivateImages && !string.IsNullOrEmpty(settings.SessionID)) &&
						!string.Equals(_StorageData[key + _PrivacyKeyName] as string, settings.SessionID, StringComparison.Ordinal))
						return buffer;

					return _StorageData[key] as byte[];
				}
				finally
				{
					_ReaderWriterLock.ReleaseReaderLock();
				}
			}

			if (settings.StorageType == ChartHttpHandlerStorageType.File)
			{
				settings.ValidateUri(key);
				if (!File.Exists(settings.Directory + key))
					return buffer;

				using (var stream = File.OpenRead(settings.Directory + key))
				{
					int num = 0;
					if (settings.PrivateImages)
					{
						var buffer2 = new byte[_PrivacyMarker.Length];
						num += _PrivacyMarker.Length;
						stream.Seek(stream.Length - num, SeekOrigin.Begin);
						stream.Read(buffer2, 0, buffer2.Length);
						if (!string.IsNullOrEmpty(settings.SessionID))
						{
							byte[] hashData = GetHashData();
							num += hashData.Length;
							byte[] buffer4 = new byte[hashData.Length];
							stream.Seek(stream.Length - num, SeekOrigin.Begin);
							stream.Read(buffer4, 0, buffer4.Length);
							if (!string.Equals(Encoding.Unicode.GetString(buffer4), Encoding.Unicode.GetString(hashData), StringComparison.Ordinal))
								return buffer;
						}
						else
						{
							if (string.Equals(Encoding.Unicode.GetString(buffer2), Encoding.Unicode.GetString(_PrivacyMarker), StringComparison.Ordinal))
								return buffer;

							num = 0;
						}
					}
					stream.Seek(0L, SeekOrigin.Begin);
					buffer = new byte[((int)stream.Length) - num];
					stream.Read(buffer, 0, buffer.Length);
				}
				return buffer;
			}
			if (settings.StorageType == ChartHttpHandlerStorageType.Cache)
				return HttpContext.Current.Cache[key] as byte[];

			this.NotSupportedStorageType(settings);
			return buffer;
		}

		void IChartStorageHandler.Save(string key, byte[] data)
		{
			var settings = ChartHttpHandler.Settings;
			if (settings.StorageType == ChartHttpHandlerStorageType.Process)
			{
				_ReaderWriterLock.AcquireWriterLock(AccessTimeout);
				try
				{
					_StorageData[key] = data;
					if (settings.PrivateImages && !string.IsNullOrEmpty(settings.SessionID))
						_StorageData[key + _PrivacyKeyName] = settings.SessionID;
				}
				finally
				{
					_ReaderWriterLock.ReleaseWriterLock();
				}
				return;
			}

			if (settings.StorageType == ChartHttpHandlerStorageType.File)
			{
				using (FileStream stream = File.Create(settings.Directory + key))
				{
					stream.Write(data, 0, data.Length);
					if (settings.PrivateImages && !string.IsNullOrEmpty(settings.SessionID))
					{
						var hashData = GetHashData();
						stream.Write(hashData, 0, hashData.Length);
						stream.Write(_PrivacyMarker, 0, _PrivacyMarker.Length);
					}
				}
					return;
			}

			if (settings.StorageType == ChartHttpHandlerStorageType.Cache)
			{
				HttpContext.Current.Cache.Add(key, data, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMilliseconds(AccessTimeout), CacheItemPriority.Low, null);
				return;
			}

			this.NotSupportedStorageType(settings);
		}
	}
}

